class_name AnomalyDetector
extends Node2D


## 异常状态检测器: 包括计算异常值的积累和衰减[br]
## 当角色（玩家和敌人）连续（3次）受到同种类型属性的伤害后会累计对应属性的异常值。 
## 异常值累计时，一段时间内（1s）没有受同类型属性伤害，异常值会
## 减少；若受到除同类型属性外的其他属性伤害，异常值会直接清零。[br]
## 当异常值积累到一定大小后，触发对应的异常效果。[br]
## [color=yellow]作为Character节点的子节点使用[/color]
## [code]
## Character
## L AnomalyDetector
##   L AnomalyState
##   L AnomalyState2
##   L ...
##   L AnomalyState_n
## [/code]


class _Data:
    var last_decay_time: int
    var last_damage_time: int
    var damage_attr_list: Array[DamageInfo.DamageAttribute]


@onready var _combustion_state: AnomalyState = $CombusitonState
@onready var _freeze_state: AnomalyState = $FreezeState
@onready var _palsy_state: AnomalyState = $PalsyState
@onready var _target: Character = get_parent()

## 记录当前触发的异常状态节点，异常效果消失后会被设置为null
var _current_state: AnomalyState = null
var _data := _Data.new()

@export var disabled: bool = false:
    set(value):
        disabled = value
        if disabled:
            process_mode = Node.PROCESS_MODE_DISABLED
        else:
            process_mode = Node.PROCESS_MODE_INHERIT
        
        if _combustion_state: _combustion_state.visible = not disabled
        if _freeze_state: _freeze_state.visible = not disabled
        if _palsy_state: _palsy_state.visible = not disabled



signal anomaly_decaying(value: int)
signal anomaly_accumulating(value: int)
signal triggered_anomaly(info: DamageInfo, type: AnomalyState.Type)



func _ready() -> void:
    _combustion_state.finished.connect(_anomaly_effect_finished)
    _freeze_state.finished.connect(_anomaly_effect_finished)
    _palsy_state.finished.connect(_anomaly_effect_finished)
    _target.handle_damage_signals.receive_damage_applied.connect(_detect_anomaly)

    _init_anomaly_state_node(_combustion_state)
    _init_anomaly_state_node(_freeze_state)
    _init_anomaly_state_node(_palsy_state)


func _process(_delta: float) -> void:
    if disabled: return

    # 异常衰减
    if _data.damage_attr_list.size() <= Constant.MAX_ANOMALY_BUFFER: return
    
    if Time.get_ticks_msec() - _data.last_damage_time > Constant.ANOMALY_DECAY_INTERVAL * 1000:
        if Time.get_ticks_msec() - _data.last_decay_time <= Constant.ANOMALY_DECAY_INTERVAL * 1000: return
        #_get_current_anomaly_item().value -= 1
        var curr_item := _get_current_anomaly_item()
        curr_item.add_modifier(-1)
        _data.last_decay_time = Time.get_ticks_msec()

        # print_debug("anomaly decay, current anomaly value: ", _get_current_anomaly_item().value)
        print_rich("[color=red]anomaly decay, current anomaly value: %f[/color]" % curr_item.value)
        anomaly_decaying.emit(int(curr_item.value))
        
        if _get_current_anomaly_item().int_value() == 0:
            _data.damage_attr_list.clear()


func _get_current_anomaly_item() -> DataItem:
    if _data.damage_attr_list.size() <= Constant.MAX_ANOMALY_BUFFER: return DataItem.create(0, 0, 0)
    match _data.damage_attr_list.back():
        DamageInfo.DamageAttribute.FIRE: return _target.data.fire_anomaly
        DamageInfo.DamageAttribute.ICE: return _target.data.ice_anomaly
        DamageInfo.DamageAttribute.THUNDER: return _target.data.thunder_anomaly
    return DataItem.create(0, 0, 0)


func _switch_state(type: AnomalyState.Type) -> void:
    match type:
        AnomalyState.Type.COMBUSTION: _current_state = _combustion_state
        AnomalyState.Type.FREEZE: _current_state = _freeze_state
        AnomalyState.Type.PALSY: _current_state = _palsy_state
    _current_state.process_mode = Node.PROCESS_MODE_INHERIT
    _current_state.show()
    _current_state.start()


func _anomaly_effect_finished() -> void:
    _current_state.process_mode = Node.PROCESS_MODE_DISABLED
    _current_state.hide()
    _current_state = null


func _detect_anomaly(info: DamageInfo) -> void:
    if disabled: return

    # 目标对象处于异常状态期间，不会检测其他异常，只用当前异常结束后再重新检测异常
    if not info.is_valid or _current_state != null: return
    
    # 异常缓冲
    if info.attribute != DamageInfo.DamageAttribute.NORMAL \
        and info.calced_damage > 0 \
        and (_data.damage_attr_list.is_empty() or info.attribute == _data.damage_attr_list.back()):
        _data.damage_attr_list.append(info.attribute)
    else:
        #_target.data.fire_anomaly.value = 0
        _get_current_anomaly_item().clear_modifiers()
        _data.damage_attr_list.clear()
    
    if _data.damage_attr_list.size() > Constant.MAX_ANOMALY_BUFFER:
        # 异常累积
        if Time.get_ticks_msec() - _data.last_damage_time <= Constant.ANOMALY_DECAY_INTERVAL * 1000:
            #_get_current_anomaly_item().value += 1
            var _curr_item := _get_current_anomaly_item()
            _curr_item.add_modifier(1)

            # print_debug("anomaly add, current anomaly value: ", _get_current_anomaly_item().value)
            print_rich("[color=red]anomaly add, current anomaly value: %f[/color]" % _curr_item.value)
            anomaly_accumulating.emit(int(_curr_item.value))
        
        # 切换异常状态
        var curr_item := _get_current_anomaly_item()
        if curr_item.value == curr_item.max_value:
            var type := AnomalyState.get_type(_data.damage_attr_list.back())
            _switch_state(type)
            _data.damage_attr_list.clear()
            curr_item.clear_modifiers()
            triggered_anomaly.emit(info, type)
            pass
    
    _data.last_damage_time = Time.get_ticks_msec()


func _init_anomaly_state_node(state: AnomalyState) -> void:
    state.hide()
    state.process_mode = Node.PROCESS_MODE_DISABLED


func has_anomaly() -> bool:
    return _current_state != null


func current_state() -> AnomalyState:
    return _current_state


# # 设置节点配置警告，脚本需是工具脚本
# func _get_configuration_warnings() -> PackedStringArray:
#     var warnings = PackedStringArray()

#     if get_scene_file_path() == "":
#         warnings.append("请从保存的场景实例化该节点，以确保正常工作")

#     return warnings
